package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @Author atguigu-mqx
 * @Description TODO
 * @Date 2023/5/13 15:40
 * @Version 1.0
 */
@Service
public class TestServiceImpl implements TestService {
    /*
    1.  在缓存中初始化一个num = 0;
    2.  获取缓存中num数据：
        true:
            对其进行+1 并写入缓存.
        false:
            直接返回
     */
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    public void testLock() {
        //  上锁：
        RLock lock = redissonClient.getLock("myLock");
        //  上锁
        //        lock.lock();
        //        lock.lock(10, TimeUnit.SECONDS);
        boolean res = false;
        try {
            //  第一个参数最大等待时间 第二个参数 过期时间 第三个参数时间单位
            res = lock.tryLock(1, 1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        if (res){
            try {
                System.out.println("获取到锁....");
                String num = this.redisTemplate.opsForValue().get("num");
                //  判断
                if (StringUtils.isEmpty(num)){
                    return;
                }
                //  对其进行+1 并写入缓存. int i = 1/0; 删除锁的命令就不会执行！
                //  进行转换
                int numValue = Integer.parseInt(num);
                this.redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
            } catch (NumberFormatException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        } else {
            testLock();
        }
        //        try {
        //            //  业务逻辑
        //            //  获取数据
        //            String num = this.redisTemplate.opsForValue().get("num");
        //            //  判断
        //            if (StringUtils.isEmpty(num)){
        //                return;
        //            }
        //            //  对其进行+1 并写入缓存. int i = 1/0; 删除锁的命令就不会执行！
        //            //  进行转换
        //            int numValue = Integer.parseInt(num);
        //            this.redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
        //        } catch (NumberFormatException e) {
        //            throw new RuntimeException(e);
        //        } finally {
        //            //  解锁
        //            lock.unlock();
        //        }
    }

    @Override
    public String readLock() {
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("myLock");
        //  获取到读锁
        RLock lock = rwlock.readLock();
        //  上锁  锁的过期时间是10s
        lock.lock(10,TimeUnit.SECONDS);
        //  从缓存中读取msg 信息
        String msg = this.redisTemplate.opsForValue().get("msg");
        //  自动释放锁： 10s
        //  返回数据。
        return msg;
    }

    @Override
    public String writeLock() {
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("myLock");
        //  获取写锁
        RLock lock = rwlock.writeLock();
        //  上锁 10s
        lock.lock(10,TimeUnit.SECONDS);
        //  将数据写入缓存中的msgkey中
        String uuid = UUID.randomUUID().toString();
        this.redisTemplate.opsForValue().set("msg",uuid);
        //  自动释放锁： 10s
        //  返回写入内容.
        return uuid;
    }


//    @Override
//    public void testLock() {
//        String uuid = UUID.randomUUID().toString();
//        //  redis setnx
//        //  redis setnx + setex = set key value ex timeout nx
//        Boolean result = this.redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS);
//        if (result){
//            //  获取数据
//            String num = this.redisTemplate.opsForValue().get("num");
//            //  判断
//            if (StringUtils.isEmpty(num)){
//                return;
//            }
//            //  对其进行+1 并写入缓存. int i = 1/0; 删除锁的命令就不会执行！
//            //  进行转换
//            int numValue = Integer.parseInt(num);
//            this.redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
//            //  判断
//            //            while (uuid.equals(this.redisTemplate.opsForValue().get("lock"))){
//            //                //  删除锁
//            //                this.redisTemplate.delete("lock");
//            //            }
//            //  声明一个lua 脚本
//            String script ="if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
//                    "then\n" +
//                    "    return redis.call(\"del\",KEYS[1])\n" +
//                    "else\n" +
//                    "    return 0\n" +
//                    "end\n";
//            //  创建对象
//            DefaultRedisScript defaultRedisScript = new DefaultRedisScript<>();
//            defaultRedisScript.setScriptText(script);
//            defaultRedisScript.setResultType(Long.class);
//            //  执行lua 脚本
//            this.redisTemplate.execute(defaultRedisScript, Arrays.asList("lock"),uuid);
//
//        }else {
//            //  等待
//            try {
//                Thread.sleep(200);
//                testLock();
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//        }
//    }
}
